#pragma once
#include "gtest/gtest.h"
#include "SGFem/ElementCalculator/Factory/ElementCalculatorFactory.h"
#include "DataStructure/Input/Material/ThermalMaterial.h"
#include "../Tria3ThermalCalculator.h"
#include "Utility/Algebra/Tools.h"


using SG::Algebra::Matrix;
using SG::Algebra::calcTriArea;
using SG::DataStructure::Common::Real;
using SG::DataStructure::FEM::ThermalMaterial;
using namespace SG::DataStructure::FEM;
using namespace SG::FEMSolver::Element;

// ElementCalculatorFactory 是否正确创建单元计算类
// 将 ElementCalculatorFactory 的 Register和生成对象测试放置在具体单元类型计算中
TEST (ElementCalculatorFactoryTest, Tria3ThermalElement)
{
    ElementCalculatorFactory::Register (ElementTypes::ELETYPE_ShellTria3, Tria3ThermalCalculator::Create);

    // Test
    auto CalculatorPtr = ElementCalculatorFactory::Create (ElementTypes::ELETYPE_ShellTria3);

    // Target data
    auto tria3Calctor = dynamic_cast<Tria3ThermalCalculator*> (CalculatorPtr.get ());

    // Check
    ASSERT_TRUE (0 != tria3Calctor);
}
extern std::shared_ptr<DBServiceFactory> DB_SERVICEFACTORY;

class Tria3ThermalCalculatorTest : public ::testing::Test
{
public:

    virtual void SetUp() override
    {
        // 指定材料属性
        k  = 1.0;  //热传导系数
        points = SG::Algebra::PointArray(3);
        points[0].m_x = 0.0;                 points[0].m_y = 1.0;                  
        points[1].m_x = 0.0;                 points[1].m_y = 0.0; 
        points[2].m_x = 1.0;                 points[2].m_y = 0.0;                 
    }

protected:
    Real k;
    SG::Algebra::PointArray points; ///< 单元节点坐标
};


TEST_F (Tria3ThermalCalculatorTest, ComputeStiffness)
{
    Tria3ThermalCalculator elementCalc;
    elementCalc.Initialize(ELETYPE_ShellTria3);

    Matrix Kel(3, 3);
    Matrix vertices(3,2);
    Real area;
    Vector3D normal;
    ThermalMaterial material;
    material.m_K = 1.0;
    Real thickness = 1.0;

    for (std::size_t iNode = 0; iNode < 3; ++iNode)
    {
        vertices(iNode, 0) = points[iNode].m_x;
        vertices(iNode, 1) = points[iNode].m_y;
    }
    
    area = calc2DTriArea(vertices, normal);

    Real areaTarget = 0.5;
    ASSERT_TRUE(area == areaTarget);

    elementCalc.ComputeStiffness(vertices, material, thickness, Kel);
    
    Matrix KelTarget(3, 3, {          
               0.50000000000000,-0.50000000000000,0.0000000000000,
               -0.50000000000000,1.0000000000000,-0.50000000000000,  
               0.0000000000000,-0.50000000000000,0.50000000000000
         });
    
    ASSERT_TRUE(Kel == KelTarget);
}